#####################################################################
# Product:      KnowledgeEngine (Plone Edition)
#
# File:         Install.py
#
# Copyright:    Copyright (c) 2004, Faulkner Technologies
#
# Author:       Brian Oliver
#
# Description:  This file defines the install() method to configure
#               the Knowledge Engine for use in a CMF Site.  It's meant
#               to be used as an External Method.
#
# ZMI Usage:    In the ZMI (Zope Management Interface)
#
#               1. Add an 'External Method' object to the root of the
#               'CMF/Plone Site' in which you wish to use 
#               KnowledgeEngines.
#
#               2. When creating the 'External Method', set it's 
#               properties to be:
#
#               id = 'KnowledgeEngineInstaller'
#               title = 'Prepares a CMF Site for use with a Knowledge Engine'
#               module name = 'KnowledgeEngine.Install'
#               function name = 'install'
#
#               3. After creation, go to the management screen of
#               the 'KnowledgeEngineInstaller' and select the 'Test'
#               tab.  This will execute the install function and
#               configure the CMF/Plone Site instance for use by
#               Knowledge Engine instances., including; 
#               i). registering appropriate content types,
#               ii). registering skins for all skinnable components.
#####################################################################

__doc__ = """Install script to setup the KnowledgeEngine in a CMF Site Instance"""

#####################################################################
## KnowledgeEngine Library Imports
from Products.KnowledgeEngine import KnowledgeEngineGlobals, getRegisteredClassInfo

#####################################################################
## Python Library Imports
from cStringIO import StringIO
import string
import copy
import os

#####################################################################
## Core Zope Imports
from OFS.Folder import Folder
from App.FindHomes import ppath
from zExceptions import BadRequest

#####################################################################
## CMF Library Imports
from Products.CMFCore.TypesTool import FactoryTypeInformation
from Products.CMFCore.DirectoryView import addDirectoryViews, createDirectoryView
from Products.CMFCore.utils import getToolByName

try:
    # Plone 3 comes with a module called 'plone'. If we can import it, assume we are running plone 3
    # (There is no proper way to check versions, so this will need to be revised every new release of plone)
    import plone
    PLONE_VERSION=3
except ImportError:
    PLONE_VERSION=2    


def install_configlet(self, out):
    """
        Installs a configlet for KnowledgeEngine to enable global properties
        such as permissions to be defined.
    """
    
    try:
        portal_conf=getToolByName(self,'portal_controlpanel')
    except AttributeError:
        print >>out, "Configlet could not be installed"
        return

    portal_conf.unregisterConfiglet( 'KnowledgeEngine Configuration Tool' )    
    portal_conf.registerConfiglet(
        'KnowledgeEngine Configuration Tool',
        "Faulkner KnowledgeEngine",
        'string:${portal_url}/knowledgeengine_tool/permissions',
        '',
        'Manage portal',
        'Products',
        1,
        'KnowledgeEngine',
        'kupuimages/kupu_icon.gif',  # TODO: Change This!
        'KnowledgeEngine Tool',
        None,
    )
    

    
    portal_conf.unregisterConfiglet( 'kedebugmode' )    
    portal_conf.registerConfiglet(
        'kedebugmode',
        "KnowledgeEngine Debug Mode",
        'string:${portal_url}/knowledgeengine_tool/prefs_debugmode',
        '',
        'Manage portal',
        'Products',
        1,
        'KnowledgeEngine',
        'kerl.png',  # TODO: Change This!
        'KnowledgeEngine Tool',
        None,
    )
    

    portal_conf.unregisterConfiglet( 'resetAuthTokens' )    
    portal_conf.registerConfiglet(
        'resetAuthTokens',
        "Reset Auth Tokens",
        'string:${portal_url}/resetAuthTokens_form',
        '',
        'View',
        'Member',
        1,
        'KnowledgeEngine',
        'clear_auth_tokens.png',  # TODO: Change This!
        'KnowledgeEngine Tool',
        None,
    )
    

def install_services(self):
    """ Installs the default knowledgeengine services """
    
    # FIXME: Zope uses titles to references the objects... bad idea. Perhaps we should internally use a different mechanism to add them?
    types = ["KnowledgeEngine: Plone Group Provider Service (uses GRUF)",
             "KnowledgeEngine: Plone User Provider Service",
             "KnowledgeEngine: MySQL Five Assessment Storage Service",
             "KnowledgeEngine: Generic Object Catalog Service",
             "KnowledgeEngine: MySQL Credit Management Service",
             "KnowledgeEngine: MySQL Security Service",
             "KnowledgeEngine Tool"]
        
    for type in types:
        try:
            self.manage_addProduct['KnowledgeEngine'].manage_addTool( type=type )
        except BadRequest:
            pass


def install(self):
    """
        Configures a CMF Site for use with a Knowledge Engine
    """
    
    #import os
    #raise `os.getcwd()` 
    
    install_services(self)
    
    product_folder = self.Control_Panel.Products.KnowledgeEngine.home
    
    try:self.portal_workflow._importObjectFromFile( product_folder + "/model_folder_workflow.zexp" )
    except:pass
    try:self.portal_workflow._importObjectFromFile( product_folder + "/model_workflow.zexp" )
    except:pass
    
   
    #self.portal_workflow.manage_changeWorkflows( 'plone_workflow', props={'chain_Model':"model_workflow"} )

    # Yay for a lack of coherent CMF API's
    # (Set the default workflow for the Model and ModelFolder in the only way possible- blatent rape of a private attribute)
    self.portal_workflow._chains_by_type[ 'Model' ]           = ['model_workflow']
    self.portal_workflow._chains_by_type[ 'KE Model Folder' ] = ['model_folder_workflow'] 


    try:self.portal_css.manage_addStylesheet( id='knowledge_engine.css', enabled=True )
    except ValueError:pass
            
    try:self.portal_css.manage_addStylesheet( id='printSimpleReport.css', enabled=True, media="print" )
    except ValueError:pass        

    #buffer all output (so we can write it to the client AND the stdout on the server)
    out = StringIO()
    out.write("\n[KnowledgeEngine] Commence: Installing Knowledge Engine for use in the Zope CMF\n")

    ######################################
    ### STEP 1: Install the Knowledge Engine skins ###    
    
    #get the special folder (SkinsTool) called 'portal_skins' where the skins are located
    lSkinsTool = getToolByName(self, 'portal_skins')
    
    ##attempt to create a KnowledgeEngine file system directory view of the 
    ##KnowledgeEngine Cache (it contains all of the skins)
    if 'KnowledgeEngine' not in lSkinsTool.objectIds():
        #create a directory view
        
        createDirectoryView(lSkinsTool, 'KnowledgeEngine/Cache', 'KnowledgeEngine')
        
                                
        out.write("[KnowledgeEngine] Created 'KnowledgeEngine' directory view layer in the 'portal_skins'\n")
    else:
        out.write("[KnowledgeEngine] Skipping layer creation: 'KnowledgeEngine' directory view already exists in the 'portal_skins'\n")

    if PLONE_VERSION == 3 and 'KnowledgeEngine_Plone3' not in lSkinsTool.objectIds():
        createDirectoryView(lSkinsTool, 'KnowledgeEngine/compat/Plone3.0', "KnowledgeEngine_Plone3")
        out.write("[KnowledgeEngine] Created 'KnowledgeEngine_Plone3' directory view layer in the 'portal_skins'\n")


    ######################################
    ### STEP 2: Register the 'KnowledgeEngine' skin folder with the 'portal_skin' Tool ###    
    
    #attempt to add the 'KnowledgeEngine' skin to each of the skin selections
    for lSkin in lSkinsTool.getSkinSelections():
    
        #get the skins path for the current skin
        lPath = lSkinsTool.getSkinPath(lSkin)
        
        #split the path (it is comma separated) so we can add a new path (to the KnowledgeEngine)
        lPath = map(string.strip, string.split(lPath,','))
        
        #ensure the KnowledgeEngine skin isn't already in the path for the current skin
        if 'KnowledgeEngine' not in lPath:
            #attempt to insert into the path after the custom skins folder 
            #(this allows the KnowledgeEngine skins to be customised but after that, the KnowledgeEngine skins take priority)
            try: 
                lPath.insert(lPath.index('custom') + 1, 'KnowledgeEngine')
            except ValueError:
                #prepend as we want the KnowledgeEngine to be first in the list if we can't add after the 'custom' skin
                lPath = ['KnowledgeEngine'] + lPath
                
            #add the necessary comma (to separate paths)                
            slPath = string.join(lPath, ', ')
            
            #re-add the skin path (updates the object so the skin path is saved)
            lSkinsTool.addSkinSelection(lSkin, slPath)
            
            out.write("[KnowledgeEngine] Added 'KnowledgeEngine' to path in skin '%s'\n" % lSkin)
            
        else:
            out.write("[KnowledgeEngine] Skipping skin '%s'. KnowledgeEngine is already in the skin path\n" % lSkin)
            
        if PLONE_VERSION == 3 and 'KnowledgeEngine_Plone3' not in lPath:            
            
            try: 
                lPath.insert(lPath.index('custom') + 1, 'KnowledgeEngine_Plone3')
            except ValueError:
                #prepend as we want the KnowledgeEngine to be first in the list if we can't add after the 'custom' skin
                lPath = ['KnowledgeEngine_Plone3'] + lPath
                
            #add the necessary comma (to separate paths)                
            slPath = string.join(lPath, ', ')
            
            #re-add the skin path (updates the object so the skin path is saved)
            lSkinsTool.addSkinSelection(lSkin, slPath)
            

    ######################################
    ### STEP 3: Register the Environment as a 'portal_type' ###    

    #get the types tool (we need to register the Environment in here)
    lTypesTool = getToolByName(self, 'portal_types')
    
    #TODO: Make this generic to use the registered portal object types!!!
    #attempt to install the type (it may fail as it is already in the portal_types)    
    #try:
    
    """
       'id'             : 'Model'
                             , 'meta_type'      : 'Model'
                             , 'description'    : "A KnowledgeEngine Model"
                             , 'icon'           : 'Model_icon.gif'
                             , 'product'        : 'KnowledgeEngine'
                             , 'factory'        : 'addModel'
                             , 'filter_content_types' : 1
                             , 'global_allow'   : 1
                             , 'immediate_view' : 'view'
    """

    def addTypeInfo( add_meta_type, id, typeinfo_name, **kw ):
                
        fti = portalInfoCatalog[id][3]
        
        
        try:
            lTypesTool.manage_addTypeInformation( add_meta_type=add_meta_type, id=id, typeinfo_name=typeinfo_name, **kw )
            
            if PLONE_VERSION==3 and fti:
                
                myfti = copy.deepcopy(fti)
                
                myfti["content_meta_type"] = id
                myfti["content_icon"]      = myfti["icon"]
                myfti["title"]             = id
                
                typeinfo = getattr(lTypesTool, id)
                typeinfo.manage_editProperties( myfti ) 
                
                
                
                for action in myfti["actions"]:                    
                    
                    action["visible"] = True                    
                    action["permission"] = action["permissions"]
                    action["condition"] = ""
                    del action["permissions"]
                    typeinfo.addAction( **action )
                 
                 
                 
                 
                 
                 
                 

            
        except BadRequest: # The tool already exists
            out.write("[KnowledgeEngine] %s already in portal types\n" % id)
        
        
    from Products.KnowledgeEngine.Core import portalInfoCatalog
    

    addTypeInfo(add_meta_type='Factory-based Type Information', id='MyKnowledgePortlet', typeinfo_name='KnowledgeEngine: MyKnowledgePortlet (MyKnowledgePortlet)')
    out.write("[KnowledgeEngine] Added 'MyKnowledgePortlet' to the 'portal_types'\n")

    addTypeInfo(add_meta_type='Factory-based Type Information', id='MySQLTableEntitySource', 
                typeinfo_name='KnowledgeEngine: MySQLTableEntitySource (MySQLTableEntitySource)')
    out.write("[KnowledgeEngine] Added 'MySQLTableEntitySource' to the 'portal_types'\n")
    
    addTypeInfo(add_meta_type='Factory-based Type Information', id='PythonEntitySource', 
                typeinfo_name='KnowledgeEngine: PythonEntitySource (PythonEntitySource)')
    out.write("[KnowledgeEngine] Added 'PythonEntitySource' to the 'portal_types'\n")

    addTypeInfo(add_meta_type='Factory-based Type Information', id='ModelEntitySource', typeinfo_name='KnowledgeEngine: ModelEntitySource (ModelEntitySource)')
    out.write("[KnowledgeEngine] Added 'ModelEntitySource' to the 'portal_types'\n")

    addTypeInfo(add_meta_type='Factory-based Type Information', id='CountryEntitySource', typeinfo_name='KnowledgeEngine: CountryEntitySource (CountryEntitySource)')
    out.write("[KnowledgeEngine] Added 'CountryEntitySource' to the 'portal_types'\n")

    

    addTypeInfo(add_meta_type='Factory-based Type Information', id='Model', typeinfo_name='KnowledgeEngine: Model (Model)')
    out.write("[KnowledgeEngine] Added 'Model' to the 'portal_types'\n")
        
    #except:
    #    out.write("[KnowledgeEngine] Skipping type 'Model'.  Already registered in the 'portal_types'\n")

    # Install configlet
    install_configlet(self, out)
    out.write("[KnowledgeEngine] Configlet installed\n")

    out.write("[KnowledgeEngine] Complete: Installed Knowledge Engine for use in the Zope CMF\n")
    
    #output the stdout
    print out.getvalue()
    
    #return the outcome to be rendered on the client browser
    return out.getvalue()

    



def uninstall(self):
    """
        Remove various bits of KE from the plone portal.
        
        TODO: This needs to include the CMF types etc in future.
    """
    out = StringIO()
    
    # Remove the configlet
    configTool = getToolByName(self, 'portal_controlpanel', None)
    if configTool:
        configTool.unregisterConfiglet('KnowledgeEngine Configuration Tool')
        out.write('Removed KnowledgeEngine configlet\n')
    
    print >> out, "Successfully uninstalled KnowledgeEngine."
    return out.getvalue()
    